/**
 * @author 陈泰来
 * @version V1.0
 * @Project echo-java-base
 * @Title 使用Lock和LinkedHashMap 实现生产消费者模型
 * @Description *
 * @Package concurrent.blockingQueue.bqtest4
 * @date 2021/3/23 11:53 上午
 * @Copyright:学如逆水行舟，不进则退 .
 */
package concurrent.blockingQueue.bqtest4;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BQTestQueue4<T> {

    public static final int MAX_QUEUE_SIZE = 50;
    public static final int EMPTY_QUEUE_SIZE = 0;

    /**
     * @Description 免锁下标
     * @Author chentl
     * @Create: 2021/3/23 1:58 下午
     */
    public static volatile Integer index = 50;
    /**
     * @Description 缓冲区可重入锁
     * @Author chentl
     * @Create: 2021/3/23 1:44 下午
     */
    private final ReentrantLock syncLock;

    /**
     * @Description 推送条件变量
     * @Author chentl
     * @Create: 2021/3/23 1:44 下午
     */
    private final Condition pushCondition;

    /**
     * @Description 消费条件变量
     * @Author chentl
     * @Create: 2021/3/23 1:44 下午
     */
    private final Condition takeCondition;

    /**
     * @Description 缓冲队列
     * @Author chentl
     * @Create: 2021/3/23 11:59 上午
     */
    private final LinkedHashMap<Integer, T> queue;

    //构造
    public BQTestQueue4(LinkedHashMap<Integer, T> queue) {
        this.syncLock = new ReentrantLock();
        this.pushCondition = this.syncLock.newCondition();
        this.takeCondition = this.syncLock.newCondition();
        this.queue = queue;
    }

    /**
     * @return void
     * @author chentl
     * @description 推送消息
     * @date 2021/3/23 1:50 下午
     * @params []
     */
    public void push(T msg) {

        if (syncLock.tryLock()) {
            try {
                //条件等待
                while (MAX_QUEUE_SIZE <= queue.size()) pushCondition.await();

                queue.put(index, msg);
                System.out.printf("下标为 %d 的消息: 【%s】 已入队,当前队列大小为: %d \n", index, msg, queue.size());

                int curIndex = index + 1;
                index = curIndex >= MAX_QUEUE_SIZE ? curIndex % MAX_QUEUE_SIZE : curIndex;

                //唤醒消费线程
                takeCondition.signalAll();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                syncLock.unlock();
            }
        } else
            System.out.println("push线程没取到锁，打会儿酱油先~");
    }

    /**
     * @return void
     * @author chentl
     * @description 消费消息
     * @date 2021/3/23 1:50 下午
     * @params []
     */
    public void take() {
        if (syncLock.tryLock()) {
            try {
                //条件等待
                while (queue.size() == EMPTY_QUEUE_SIZE) takeCondition.await();

                Iterator<Map.Entry<Integer, T>> iterator = queue.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<Integer, T> entry = iterator.next();
                    iterator.remove();

                    System.out.printf("消费下标为: %d 的元素： %s \n", entry.getKey(), entry.getValue());
                }

                //唤醒推送线程
                pushCondition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                syncLock.unlock();
            }
        } else
            System.out.println("take线程没取到锁，打会儿酱油先~");

    }


    public static void main(String[] args) {
        BQTestQueue4<String> queue = new BQTestQueue4<>(new LinkedHashMap<>());
        Thread consumer = new Thread(new Consumer(queue));
        Thread producer = new Thread(new Producer(queue));

        consumer.start();
        producer.start();

    }
}
